#include "console.h"
#include "string.h"
#include "cpu.h"
#define MAXCOL 80
#define MAXLIG 25
#define BEG (void*)0xB8000
#define CMD_LOW 0x0F
#define CMD_HIGH 0x0E
#define PORT_CMD 0x3D4
#define PORT_DATA 0x3D5
#define GRIS 7

int cur_column = -1;
int cur_line = -1;


short* ptr_mem(int lig, int col)
{
	return (short*)(BEG + sizeof(short) * (lig * MAXCOL + col));
}

void ecrit_car(int lig, int col, char c)
{
	// c white with black background
	short* ptr_char = ptr_mem(lig, col);
	*ptr_char = 0;
	*ptr_char = (GRIS) << 8 | c;

	// last line AND column -> scroll!
	if((cur_column == MAXCOL -1) && (cur_line == MAXLIG - 1)){
		defilement();
		cur_column = 0;
		place_curseur(cur_line, cur_column);
	}
	else if(cur_column == MAXCOL){ // last column -> move next line
			cur_column = 0;
			cur_line += 1;
			place_curseur(cur_line, cur_column);
	}
	else{
		// normal situation -> move next column
		cur_column += 1;
		place_curseur(cur_line, cur_column);
	}
}

void place_curseur(int lig, int col)
{
	unsigned short pos = col + lig * MAXCOL;

	// send low part command and data;
	outb(CMD_LOW, PORT_CMD);
    unsigned char pos_low = (pos<<8)>>8;
	outb(pos_low, PORT_DATA);

	// send high part command and data;
	outb(CMD_HIGH, PORT_CMD);
    unsigned char pos_high = pos >> 8;
	outb(pos_high, PORT_DATA);
}

void efface_ecran(void)
{
	memset(BEG, 0,  sizeof(short)*(MAXLIG * MAXCOL));
	cur_column = cur_line = 0;
	place_curseur(cur_line, cur_column);
}

void console_putbytes(const char *s, int len)
{
	if(cur_column == -1){
		efface_ecran();
	}

	for(int i = 0; i < len; i++){
		traite_car(s[i]);
	}
}

void traite_car(char c)
{
	if(c == '\b'){
		if(cur_column != 0){
			cur_column -= 1;
			place_curseur(cur_line, cur_column);
		}
	}

	if(c == '\t'){
		cur_column += 8;
		place_curseur(cur_line, cur_column);
	}

	if(c == '\n'){
		if(cur_line == MAXLIG - 1){ // if last line.
			defilement();
			cur_column = 0;
			place_curseur(cur_line, cur_column);
		}
		else{
			// normal sit.
			cur_line += 1;
			cur_column = 0;
			place_curseur(cur_line, cur_column);
		}
	}

	if(c == '\f'){
		efface_ecran();
		place_curseur(0,0);
	}

	if(c == '\r'){
		cur_column = 0;
		place_curseur(cur_line, cur_column);
	}
	if((c >= ' ') && (c <= '~')){
		ecrit_car(cur_line, cur_column, c);
	}
}

void defilement(void)
{   // move 2000 elements from line 1, column 0 to line 0.
	memmove(ptr_mem(0,0), ptr_mem(1,0), sizeof(short)*(MAXLIG * MAXCOL));
}

